﻿/**
 * Copyright (c) 2011 Sylvain Gougouzian (sylvain@gougouzian.fr)
 * MIT (http://www.opensource.org/licenses/mit-license.php) licensed.
 * GNU GPL (http://www.gnu.org/licenses/gpl.html) licensed.
 */
jQuery(function($){
	$.fn.moodulite = function(options){
		var el = null;
		var opts = $.extend({}, $.fn.moodulite.defaults, options);
		var ctrls = $.extend({}, $.fn.moodulite.controls);
		var effects = $.extend({}, $.fn.moodulite.effects);
		this.each(function(){
			el = new $moodulite(this, opts, ctrls, effects);
		});
		return opts.api ? el : null;
	};
	$.moodulite = function(e, opts, ctrls, effects){
		this.e = $(e);
		if (opts.random) {
			var elems = $('> ' + opts.item, this.e);
			elems.sort(function(){return (Math.round(Math.random())-0.5);});
			this.e.html('');
			for(var i=0; i < elems.length; i++)
				this.e.append(elems[i]);
		}
		this.aItems = $('> ' + opts.item, this.e);
		this.nbItems = this.aItems.length;
		this.current = 0;
		this.dir = 1;
		this.locked = false;
		this.temp = new Array();
		this.timerMoving = null;
		this.opts = opts;
		this.controls = ctrls;
		this.effects = effects;
		this.tmp = -1;
		this.reverse = false;
		this._init();
	};
	var $moodulite = $.moodulite;
	$moodulite.fn = $moodulite.prototype = {
		moodulite: '1.0'
	};
	$moodulite.fn.extend = $moodulite.extend = $.extend;
	$moodulite.fn.extend({
		_init: function(){
			var self = this;
			this.e.wrap('<div></div>');
			this.e.parent().css({
				'position' : 'relative',
				'overflow' : 'hidden',
				'width'	: this.e.width(),
				'height' : this.e.height()
			});
			this.e.css({
				'position' : 'absolute',
				'left' : 0,
				'top' : 0
			});
			this.control = this.opts.controls.split(' ');
			this.effect = this.opts.effects.split(' ');
			this._resize();
			$(window).bind('resize', function () { self._resize(); });
			var i;
			for (i = 0; i < this.control.length; i++) {
				if ($.isFunction(this.controls.init[this.control[i]]))
					this.controls.init[this.control[i]](this);
			}
			for (i = 0; i < this.effect.length; i++) {
				if ($.isFunction(this.effects.init[this.effect[i]]))
					this.effects.init[this.effect[i]](this);
			}
			if (this.opts.auto) {
				this.timerMoving = setTimeout(function(){
					self._animate();
				}, self.opts.dispTimeout);
			}
		},
		_resize: function () {
			var i;
			for (i = 0; i < this.effect.length; i++) {
				if ($.isFunction(this.effects.resize[this.effect[i]]))
					this.effects.resize[this.effect[i]](this);
				else {
					this.size = parseInt(this.e.parent().width());
					this.e.width(2 * this.size + 'px');
					$('>' + this.opts.item, this.e).width(this.size);
				}
			}
		},
		_animate: function(){
			if (!this.locked) {
				this.locked = true;
				clearTimeout(this.timerMoving);
				var cont = true;
				if (!this.opts.continuous) {
					if (this.dir == 1) {
						if (this.current >= (this.nbItems - 1))
							cont = false;
					}
					else {
						if (this.current <= 0)
							cont = false;
					}
				}
				if (cont)
					this._move();
				else
					this.stop();
			}
		},
		_move: function(){
			var i;
			for (i = 0; i < this.control.length; i++) {
				if ($.isFunction(this.controls.before[this.control[i]]))
					this.controls.before[this.control[i]](this);
			}
			for (i = 0; i < this.effect.length; i++) {
				if ($.isFunction(this.effects.before[this.effect[i]]))
					this.effects.before[this.effect[i]](this);
			}
			var self = this;
			if (this.notMoving)
				this._afterMoving();
			else {
				if ($.isFunction(this.opts.move)) {
					this.locked = true;
					this.opts.move(this, function(){
						self._afterMoving();
					});
				} else {
					this._afterMoving();
				}
			}
		},
		_afterMoving: function(){
			var self = this;
			this.current += this.dir;
			if (this.current == -1) {
				if (this.opts.continuous)
					this.current = this.nbItems - 1;
				else
					this.current = 0;
			}
			else {
				if (this.current == this.nbItems) {
					this.current = 0;
				}
			}
			for (i = 0; i < this.control.length; i++) {
				if ($.isFunction(this.controls.after[this.control[i]]))
					this.controls.after[this.control[i]](this);
			}
			for (i = 0; i < this.effect.length; i++) {
				if ($.isFunction(this.effects.after[this.effect[i]]))
					this.effects.after[this.effect[i]](this);
			}
			for (i = 0; i < this.opts.callbacks.length; i++) {
				this.opts.callbacks[i](this);
			}
			if (this.tmp != -1) {
				var t = this.nbItems - this.current + this.tmp;
				if (t != this.nbItems)
					$('> ' + this.opts.item, this.e).eq(t - 1).after($('> ' + this.opts.item + ':last', this.e));
				this.tmp = -1;
			}
			this.locked = false;
			this.dir = 1;
			if (this.opts.auto) {
				this.timerMoving = setTimeout(function(){
					self._animate();
				}, this.opts.dispTimeout);
			}
		},
		start: function(){
			if (!this.opts.auto) {
				this.locked = false;
				this.opts.auto = true;
				this._animate('next');
			}
			return false;
		},
		stop: function(){
			clearTimeout(this.timerMoving);
			this.opts.auto = false;
			this.locked = false;
			return false;
		},
		next: function(){
			this.moveTo(this.current + 1);
			return false;
		},
		prev: function(){
			this.dir = -1;
			this.moveTo(this.current - 1);
			return false;
		},
		moveTo: function (n) {
			if (!this.locked) {
				var i, j;
				j = n - this.current - 1;
				if (j < 0) j += this.nbItems;
				if (j != (this.nbItems - 1)) {
					for(i = 0; i < j; i++) {
						if (this.reverse || this.dir == -1)
							this.e.prepend($('> ' + this.opts.item, this.e).eq(1));
						else
							this.e.append($('> ' + this.opts.item, this.e).eq(1));
					}
					this.tmp = this.current;
					this.current = n - this.dir;
					if (this.current == -1) this.current += this.nbItems;
					this._animate();
				}
			}
		}
	});
	$.fn.moodulite.defaults = {
		item: 'li',
		controls: '',
		effects: 'left',
		easing: '',
		auto: true,
		continuous: true,
		speed: 2000,
		dispTimeout: 1000,
		callbacks: [],
		random: false,
		api: false
	};
	$.fn.moodulite.controls = {
		callback: {}
	};
	$.fn.moodulite.effects = {
		init: {
			left: function (m) {
				m.opts.move = function (c, b) {
					c.e.animate({
						left: (c.dir == 1 ? '-=' : '+=') + c.size + 'px'
					}, c.opts.speed, c.opts.easing, function () {
						b();
					});
				}
			}
		},
		before: {
			left: function (m) {
				if (m.dir == -1) {
					m.e.prepend($('> ' + m.opts.item + ':last', m.e));
					m.e.css('left', '-' + m.size + 'px');
				}
			}
		},
		after: {
			left: function (m) {
				if (m.dir == 1) {
					m.e.append($('> ' + m.opts.item + ':first', m.e));
					m.e.css('left', 0);
				}
			}
		},
		resize: {
		}
	};
	$.fn.moodulite.controls = {
		init: {},
		before: {},
		after: {}
	};
});